package deque;

import org.junit.Test;

import java.util.Optional;

import static org.junit.Assert.*;


/** Performs some basic linked list tests. */
public class ArrayDequeTest {

    @Test
    /** Adds a few things to the list, checking isEmpty() and size() are correct,
     * finally printing the results.
     *
     * && is the "and" operation. */

    public void addTest() {
        ArrayDeque<Integer> deque = new ArrayDeque<>();

        // 在前端添加元素
        deque.addFirst(10);
        deque.addFirst(20);
        deque.addFirst(30);

        // 打印当前 deque 中的元素
        System.out.println(deque.size());
        deque.printDeque();

        assertEquals(10, (int)deque.get(2));
        assertEquals(20, (int)deque.get(1));
        assertEquals(30,(int) deque.get(0));

        assertTrue("A newly initialized LLDeque should be empty", deque.get(0) == 30);
        assertTrue("A newly initialized LLDeque should be empty", deque.get(1) == 20);
        assertTrue("A newly initialized LLDeque should be empty", deque.get(2) == 10);

    }
    @Test
    public void addLastTest() {
        ArrayDeque<Integer> deque = new ArrayDeque<>();

        // 在前端添加元素
        deque.addLast(10);
        deque.addLast(20);
        deque.addLast(30);

        // 打印当前 deque 中的元素
        System.out.println(deque.size());
        deque.printDeque();

        assertEquals(10, (int)deque.get(0));
        assertEquals(20, (int)deque.get(1));
        assertEquals(30,(int) deque.get(2));


    }
    @Test
    public void removeFirstTest() {
        ArrayDeque<Integer> deque = new ArrayDeque<>();

        // 在前端添加元素
        deque.addLast(10);
        deque.addLast(20);
        deque.addLast(30);
        deque.addLast(40);
        deque.addLast(50);


        // 打印当前 deque 中的元素
        System.out.println(deque.size());
        deque.printDeque();
        deque.removeFirst();
        assertEquals(20, (int)deque.get(0));
        assertEquals(30, (int)deque.get(1));
        assertEquals(40,(int) deque.get(2));

        System.out.println(deque.size());
        deque.printDeque();


    }
    @Test
    public void removeLastTest() {
        ArrayDeque<Integer> deque = new ArrayDeque<>();

        // 在前端添加元素
        deque.addLast(10);
        deque.addLast(20);
        deque.addLast(30);
        deque.addLast(40);
        deque.addLast(50);


        // 打印当前 deque 中的元素
        System.out.println(deque.size());
        deque.printDeque();
        deque.removeLast();
        assertEquals(10, (int)deque.get(0));
        assertEquals(20, (int)deque.get(1));
        assertEquals(40,(int) deque.get(3));
//        assertEquals(null,(int) deque.get(4));

        System.out.println(deque.size());
        deque.printDeque();


    }
    @Test
    public void addManyTest() {
        ArrayDeque<Integer> deque = new ArrayDeque<>();

        // 在前端添加元素
        deque.addLast(10);
        deque.addLast(20);
        deque.addLast(30);
        deque.addLast(40);
        deque.addLast(50);
        deque.addLast(60);
        deque.addLast(70);
        deque.addLast(80);
        deque.addLast(90);
        deque.addLast(91);
        deque.addLast(92);
        deque.addLast(93);

        // 打印当前 deque 中的元素
        System.out.println(deque.size());
        deque.printDeque();

        assertEquals(10, (int)deque.get(0));
        assertEquals(20, (int)deque.get(1));
        assertEquals(30,(int) deque.get(2));
        assertEquals(93,(int) deque.get(11));


    }
    @Test
    public void addIsEmptySizeTest() {

        System.out.println("Make sure to uncomment the lines below (and delete this print statement).");

        ArrayDeque<String> lld1 = new ArrayDeque<String>();

        assertTrue("A newly initialized LLDeque should be empty", lld1.isEmpty());
        lld1.addFirst("front");

        // The && operator is the same as "and" in Python.
        // It's a binary operator that returns true if both arguments true, and false otherwise.
        assertEquals(1, lld1.size());
        assertFalse("lld1 should now contain 1 item", lld1.isEmpty());

        lld1.addLast("middle");
        assertEquals(2, lld1.size());

        lld1.addLast("back");
        assertEquals(3, lld1.size());

        System.out.println("Printing out deque: ");
        lld1.printDeque();

    }


    @Test
    /** Adds an item, then removes an item, and ensures that dll is empty afterwards. */
    public void addRemoveTest() {

        System.out.println("Make sure to uncomment the lines below (and delete this print statement).");

        ArrayDeque<Integer> lld1 = new ArrayDeque<Integer>();
        // should be empty
        assertTrue("lld1 should be empty upon initialization", lld1.isEmpty());

        lld1.addFirst(10);
        // should not be empty
        assertFalse("lld1 should contain 1 item", lld1.isEmpty());

//        lld1.removeFirst();
//        // should be empty
//        assertTrue("lld1 should be empty after removal", lld1.isEmpty());

    }

    @Test
    /* Tests removing from an empty deque */
    public void removeEmptyTest() {

        System.out.println("Make sure to uncomment the lines below (and delete this print statement).");
        /*
        ArrayDeque<Integer> lld1 = new ArrayDeque<>();
        lld1.addFirst(3);

        lld1.removeLast();
        lld1.removeFirst();
        lld1.removeLast();
        lld1.removeFirst();

        int size = lld1.size();
        String errorMsg = "  Bad size returned when removing from empty deque.\n";
        errorMsg += "  student size() returned " + size + "\n";
        errorMsg += "  actual size() returned 0\n";

        assertEquals(errorMsg, 0, size);
        */
    }

    @Test
    /* Check if you can create ArrayDeques with different parameterized types*/
    public void multipleParamTest() {


        ArrayDeque<String>  lld1 = new ArrayDeque<String>();
        ArrayDeque<Double>  lld2 = new ArrayDeque<Double>();
        ArrayDeque<Boolean> lld3 = new ArrayDeque<Boolean>();

        lld1.addFirst("string");
        lld2.addFirst(3.14159);
        lld3.addFirst(true);

        String s = lld1.removeFirst();
        double d = lld2.removeFirst();
        boolean b = lld3.removeFirst();

    }

    @Test
    /* check if null is return when removing from an empty ArrayDeque. */
    public void emptyNullReturnTest() {

        System.out.println("Make sure to uncomment the lines below (and delete this print statement).");

        ArrayDeque<Integer> lld1 = new ArrayDeque<Integer>();

        boolean passed1 = false;
        boolean passed2 = false;
        assertEquals("Should return null when removeFirst is called on an empty Deque,", null, lld1.removeFirst());
        assertEquals("Should return null when removeLast is called on an empty Deque,", null, lld1.removeLast());


    }

    @Test
    /* Add large number of elements to deque; check if order is correct. */
    public void bigLLDequeTest() {

        System.out.println("Make sure to uncomment the lines below (and delete this print statement).");

        ArrayDeque<Integer> lld1 = new ArrayDeque<Integer>();
        for (int i = 0; i < 1000000; i++) {
            lld1.addLast(i);
        }

        for (double i = 0; i < 500000; i++) {
            assertEquals("Should have the same value", i, (double) lld1.removeFirst(), 0.0);
        }

        for (double i = 999999; i > 500000; i--) {
            assertEquals("Should have the same value", i, (double) lld1.removeLast(), 0.0);
        }


    }
    @Test
    public void finalTest() {
        ArrayDeque<Integer> deque = new ArrayDeque<Integer>();

        deque.addLast(10);
        deque.addLast(20);
        deque.addLast(30);
        deque.addLast(40);
        deque.addLast(50);
        deque.addLast(60);
        deque.addLast(70);
        deque.addLast(80);
        deque.addLast(90);

        Integer i = deque.removeFirst();
        Integer j = deque.removeLast();
        assertNotEquals(null,i);
        assertNotEquals(null,j);







    }
}
